Part 1: RNA
Load RNA samples
Out of 30 samples, we selected 17 for this study. These are the normal tissue samples form the control, the UVA and the UVA+SFN treatment groups. normal tissue samples from the UVB_UA groups as well as tumor samples were excluded from this analysis. Additionally, one of the control samples at Week 2 (baseline) was removed after outlier analysis.
7,219 genes with zero counts in > 80% (> 13 out of 18) of samples were removed. 17,202 out of 24,421 genes were left.
[1] 7219
[1] 17202
Transcripts per kilobase million (TPM) normalization
Next, we noramized the counts. To convert number of hits to the relative abundane of genes in each sample, we used transcripts per kilobase million (TPM) normalization, which is as following for the j-th sample:
1. normilize for gene length: a[i, j] = 1,000*count[i, j]/gene[i, j] length(bp)
2. normalize for seq depth (i.e. total count): a(i, j)/sum(a[, j])
3. multiply by one million
A very good comparison of normalization techniques can be found at the following video:
RPKM, FPKM and TPM, clearly explained
After the normalization, each sample’s total is 1M:
02w_CON_0 02w_SFN_0 02w_SFN_1 02w_UVB_0 02w_UVB_1 15w_CON_0 15w_CON_1 15w_SFN_0 15w_SFN_1 15w_UVB_0 15w_UVB_1 25w_CON_0
1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06
25w_CON_1 25w_SFN_0 25w_SFN_1 25w_UVB_0 25w_UVB_1
1e+06 1e+06 1e+06 1e+06 1e+06
Top 100 most abundant RNA molecules
# Separate top 100 abundant genes
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[(nrow(tpm) - 99):nrow(tpm)]])
tmp <- melt.data.table(data = tmp,
id.vars = 1:2,
measure.vars = 3:ncol(tmp),
variable.name = "Sample",
value.name = "TPM")
tmp$Week <- substr(x = tmp$Sample,
start = 1,
stop = 3)
tmp$Week <- factor(tmp$Week,
levels = unique(tmp$Week))
tmp$Treatment <- substr(x = tmp$Sample,
start = 5,
stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
levels = c("CON",
"UVB",
"SFN"))
tmp$Replica <- substr(x = tmp$Sample,
start = 9,
stop = 9)
tmp$Replica <- factor(tmp$Replica,
levels = 0:1)
# Plot top 100 abundant genes
p2 <- ggplot(tmp,
aes(x = TPM,
y = Geneid,
fill = Treatment,
shape = Week)) +
# facet_wrap(~ Sex, nrow = 1) +
geom_point(size = 3,
alpha = 0.5) +
geom_vline(xintercept = 1,
linetype = "dashed")
ggplotly(p2)
Bottom 100 least abundant RNA molecules
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[1:100]])
tmp <- melt.data.table(data = tmp,
id.vars = 1:2,
measure.vars = 3:ncol(tmp),
variable.name = "Sample",
value.name = "TPM")
tmp$Week <- substr(x = tmp$Sample,
start = 1,
stop = 3)
tmp$Week <- factor(tmp$Week,
levels = unique(tmp$Week))
tmp$Treatment <- substr(x = tmp$Sample,
start = 5,
stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
levels = c("CON",
"UVB",
"SFN"))
tmp$Replica <- substr(x = tmp$Sample,
start = 9,
stop = 9)
tmp$Replica <- factor(tmp$Replica,
levels = 0:1)
# Plot top 100 abundant genes
p3 <- ggplot(tmp,
aes(x = TPM,
y = Geneid,
fill = Treatment,
shape = Week)) +
# facet_wrap(~ Sex, nrow = 1) +
geom_point(size = 3,
alpha = 0.5) +
geom_vline(xintercept = 1,
linetype = "dashed")
ggplotly(p3)
PCA of TPM
NOTE: the distributions are skewed. To make them symmetric, log transformation is often applied. However, there is an issue of zeros. In this instance, we added a small values lambda[i] equal to 1/10 of the smallest non-zero value of i-th gene.
dm.tpm <- as.matrix(tpm[, -c(1:2), with = FALSE])
rownames(dm.tpm) <- tpm$Geneid
# # Remove 02w_CON_1 sample and redo PCA
# dm.tpm <- dm.tpm[, colnames(dm.tpm) != "02w_CON_1"]
# dmeta <- dmeta[dmeta$Sample != "02w_CON_1", ]
# Add lambdas to all values, then take a log
dm.ltpm <- t(apply(X = dm.tpm,
MARGIN = 1,
FUN = function(a) {
lambda <- min(a[a > 0])/10
log(a + lambda)
}))
# PCA----
m1 <- prcomp(t(dm.ltpm),
center = TRUE,
scale. = TRUE)
s1 <- summary(m1)
s1
Importance of components:
PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12
Standard deviation 66.5041 61.8206 45.2845 30.42909 28.24422 26.84136 25.01865 23.05989 22.08373 21.24391 20.87624 20.6980
Proportion of Variance 0.2571 0.2222 0.1192 0.05383 0.04637 0.04188 0.03639 0.03091 0.02835 0.02624 0.02534 0.0249
Cumulative Proportion 0.2571 0.4793 0.5985 0.65232 0.69869 0.74058 0.77696 0.80788 0.83623 0.86246 0.88780 0.9127
PC13 PC14 PC15 PC16 PC17
Standard deviation 20.28169 19.42403 19.14803 18.61200 2.085e-13
Proportion of Variance 0.02391 0.02193 0.02131 0.02014 0.000e+00
Cumulative Proportion 0.93662 0.95855 0.97986 1.00000 1.000e+00
Pareto chart of variance explained by principal components
imp <- data.table(PC = colnames(s1$importance),
Variance = 100*s1$importance[2, ],
Cumulative = 100*s1$importance[3, ])
imp$PC <- factor(imp$PC,
levels = imp$PC)
p1 <- ggplot(imp,
aes(x = PC,
y = Variance)) +
geom_bar(stat = "identity",
fill = "grey",
color = "black") +
geom_line(aes(y = rescale(Cumulative,
to = c(min(Cumulative)*30/100,
30)),
group = rep(1, nrow(imp)))) +
geom_point(aes(y = rescale(Cumulative,
to = c(min(Cumulative)*30/100,
30)))) +
scale_y_continuous("% Variance Explained",
breaks = seq(0, 30, by = 5),
labels = paste(seq(0, 30, by = 5),
"%",
sep = ""),
sec.axis = sec_axis(trans = ~.,
name = "% Cumulative Variance",
breaks = seq(0, 30, length.out = 5),
labels = paste(seq(0, 100, length.out = 5),
"%",
sep = ""))) +
scale_x_discrete("") +
theme(axis.text.x = element_text(angle = 90,
hjust = 1))
# Save for publication
tiff(filename = "tmp/pca_pareto.tiff",
height = 6,
width = 8,
units = 'in',
res = 600,
compression = "lzw+p")
print(p1)
graphics.off()
print(p1)

First 3 principal components, pairwise
# Biplot while keep only the most important variables (Javier)----
# Select PC-s to pliot (PC1 & PC2)
choices <- c(1:3)
# Scores, i.e. points (df.u)
dt.scr <- data.table(m1$x[, choices])
# Add grouping variables
dt.scr$trt <- dmeta$trt
dt.scr$time <- dmeta$time
dt.scr$sample <- dmeta$Sample
# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)
# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[choices],
sprintf('(%0.1f%% explained var.)',
100*m1$sdev[choices]^2/sum(m1$sdev^2)))
p1 <- ggplot(data = dt.scr,
aes(x = PC1,
y = PC2,
color = trt,
shape = time)) +
geom_point(size = 4,
alpha = 0.5) +
scale_x_continuous(u.axis.labs[1]) +
scale_y_continuous(u.axis.labs[2]) +
theme(legend.position = "none")
ggplotly(p1)
p2 <- ggplot(data = dt.scr,
aes(x = PC1,
y = PC3,
color = trt,
shape = time)) +
geom_point(size = 4,
alpha = 0.5) +
scale_x_continuous(u.axis.labs[1]) +
scale_y_continuous(u.axis.labs[3]) +
theme(legend.position = "none")
ggplotly(p2)
p3 <- ggplot(data = dt.scr,
aes(x = PC2,
y = PC3,
color = trt,
shape = time)) +
geom_point(size = 4,
alpha = 0.5) +
scale_x_continuous(u.axis.labs[2]) +
scale_y_continuous(u.axis.labs[3]) +
theme(legend.position = "none")
ggplotly(p3)
# Legend only
tmp <- ggplot(data = dt.scr,
aes(x = PC1,
y = PC2,
color = trt,
shape = time)) +
geom_point() +
scale_color_discrete("Treatment") +
scale_shape_discrete("Week")
p4 <- as_ggplot(get_legend(tmp))
# Save for publication
tiff(filename = "tmp/pca.tiff",
height = 7,
width = 9,
units = 'in',
res = 600,
compression = "lzw+p")
grid.arrange(p1, p2, p3, p4,
nrow = 2)
graphics.off()
First 3 principal components, 3D
scatterplot3js(x = dt.scr$PC1,
y = dt.scr$PC2,
z = dt.scr$PC3,
color = as.numeric(dt.scr$trt),
renderer = "auto",
pch = dt.scr$sample,
size = 0.1)
Differential expression analysis (DESeq2 pipeline)
Sources:
1. Analyzing RNA-seq data with DESeq2:Interactions
2. Bioconductor Question: DESeq2 time series analysis
We are testing a model with time*treatment interaction. The idea here is to find genes with significant interaction term. That would suggest that the gene expressiondifferences between the treatments depended on time. THere are several possible scenarios:
a. No difference between the negative control and the positive control groups at baseline, significant difference at the later time point. This will show the effect of the disease (UVB radiation, in this case).
b. Significant difference between the control groups at baseline, no difference at the later time point. Same as (a) above.
c. Differences between the positive control and the SFN-treated groups. Here, we are interested in the reversal of UVB effect. Again, the interaction term will need to be significant for the reasons described above.
# Relevel: make all comparisons with the positive control (UVB)
dmeta$trt <- factor(dmeta$trt,
levels = c("UVB",
"CON",
"SFN"))
dtm<- as.matrix(dt1[, dmeta$Sample,
with = FALSE])
rownames(dtm) <- dt1$Geneid
dds <- DESeqDataSetFromMatrix(countData = dtm,
colData = dmeta,
~ time + trt + time:trt)
# If all samples contain zeros, geometric means cannot be
# estimated. Change default 'type = "ratio"' to 'type = "poscounts"'.
# Type '?DESeq2::estimateSizeFactors' for more details.
dds <- estimateSizeFactors(object = dds,
type = "poscounts")
# Run DESeq----
dds <- DESeq(object = dds,
# test = "LRT",
# reduced = ~ time + trt,
fitType = "local",
sfType = "ratio",
parallel = FALSE)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
# NOTE (from DESeq help file, section Value):
# A DESeqDataSet object with results stored as metadata columns.
# These results should accessed by calling the results function.
# By default this will return the log2 fold changes and p-values
# for the last variable in the design formula.
# See results for how to access results for other variables.
# In this case, the last term is the interaction term trt:time
# NOTE:
# Likelihood ratio test (LRT) (chi-squared test) for GLM will only return
# the results for the difference between the full and the reduced model
resultsNames(dds)
[1] "Intercept" "time_15w_vs_02w" "time_25w_vs_02w" "trt_CON_vs_UVB" "trt_SFN_vs_UVB" "time15w.trtCON" "time25w.trtCON"
[8] "time15w.trtSFN" "time25w.trtSFN"
# Model matrix
mm1 <- model.matrix(~ time + trt + time:trt, dmeta)
mm1
(Intercept) time15w time25w trtCON trtSFN time15w:trtCON time25w:trtCON time15w:trtSFN time25w:trtSFN
1 1 0 0 1 0 0 0 0 0
2 1 0 0 0 1 0 0 0 0
3 1 0 0 0 1 0 0 0 0
4 1 0 0 0 0 0 0 0 0
5 1 0 0 0 0 0 0 0 0
6 1 1 0 1 0 1 0 0 0
7 1 1 0 1 0 1 0 0 0
8 1 1 0 0 1 0 0 1 0
9 1 1 0 0 1 0 0 1 0
10 1 1 0 0 0 0 0 0 0
11 1 1 0 0 0 0 0 0 0
12 1 0 1 1 0 0 1 0 0
13 1 0 1 1 0 0 1 0 0
14 1 0 1 0 1 0 0 0 1
15 1 0 1 0 1 0 0 0 1
16 1 0 1 0 0 0 0 0 0
17 1 0 1 0 0 0 0 0 0
attr(,"assign")
[1] 0 1 1 2 2 3 3 3 3
attr(,"contrasts")
attr(,"contrasts")$time
[1] "contr.treatment"
attr(,"contrasts")$trt
[1] "contr.treatment"
Results
Effect of UVB at Week 2
res_con_uvb_week2 <- results(dds,
contrast = c(0,0,0,1,0,0,0,0,0),
alpha = 0.1)
res_con_uvb_week2 <- res_con_uvb_week2[order(res_con_uvb_week2$padj,
decreasing = FALSE),]
summary(res_con_uvb_week2)
out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up) : 1546, 9%
LFC < 0 (down) : 1537, 8.9%
outliers [1] : 0, 0%
low counts [2] : 2335, 14%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_con_uvb_week2$padj < 0.1,
na.rm = TRUE)
[1] 3083
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_con_uvb.tiff",
height = 6,
width = 7,
units = 'in',
res = 600,
compression = "lzw+p")
plotMA(res_con_uvb_week2,
main = "Control vs. UVB at Week 2",
alpha = 0.8)
graphics.off()
plotMA(res_con_uvb_week2,
main = "Control vs. UVB at Week 2",
alpha = 0.8)

Protective effect of SFN at Week 2
res_sfn_uvb_week2 <- results(dds,
contrast = c(0,0,0,0,1,0,0,0,0),
alpha = 0.1)
res_sfn_uvb_week2 <- res_sfn_uvb_week2[order(res_sfn_uvb_week2$padj,
decreasing = FALSE),]
summary(res_sfn_uvb_week2)
out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up) : 26, 0.15%
LFC < 0 (down) : 35, 0.2%
outliers [1] : 0, 0%
low counts [2] : 3669, 21%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week2$padj < 0.1,
na.rm = TRUE)
[1] 61
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_sfn_uvb.tiff",
height = 6,
width = 7,
units = 'in',
res = 600,
compression = "lzw+p")
print(plotMA(res_sfn_uvb_week2,
main = "UVB+SFN vs UVB at Week 2",
alpha = 0.8))
NULL
graphics.off()
print(plotMA(res_sfn_uvb_week2,
main = "UVB+SFN vs UVB at Week 2",
alpha = 0.8))
NULL

Genes that were significantly differentiated at both timepoints
lgene.w2.con <- unique(res_con_uvb_week2@rownames[res_con_uvb_week2$padj < 0.1])
lgene.w2.sfn <- unique(res_sfn_uvb_week2@rownames[res_sfn_uvb_week2$padj < 0.1])
lgene.w2 <- lgene.w2.con[lgene.w2.con %in% lgene.w2.sfn]
lgene.w2 <- lgene.w2 [!is.na(lgene.w2 )]
lgene.w2
[1] "Utrn" "Stom" "Tesc" "Cited4" "Cdhr1" "Slc7a11" "Mki67" "Cyp26b1" "Smc2" "Mad2l1" "Slc4a7" "Ankrd23"
[13] "Ifitm3" "Etv3" "Pla2g4d" "Fetub" "Kif11" "Ccl6" "Has3" "Il19" "A4galt" "Otud1" "Msn" "Nqo1"
[25] "Dbf4" "Cblb" "Tbc1d24" "Elmo2" "Cd163" "Esd" "Rfx2" "Gsta1" "Slurp1" "Arntl2" "Vldlr" "Tmem173"
[37] "Gpx2" "Slfn9" "Adh7" "Sprr2i" "Bcl2l15"
Plot of DESeq-normalizedcounts of genes significant in both comparisons at Week 2:
# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene.w2)) {
out <- plotCounts(dds,
gene = lgene.w2[[i]],
intgroup = c("trt",
"time"),
returnData = TRUE)
dp1[[i]] <- data.table(Geneid = lgene.w2[[i]],
Sample = rownames(out),
out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
levels = c("CON",
"UVB",
"SFN"))
dp1$time <- factor(dp1$time,
levels = c("02w",
"15w",
"25w"),
labels = c("Week 2",
"Week 15",
"Week 25"))
dp1$Geneid <- factor(dp1$Geneid,
levels = lgene.w2)
dp1[, mu := mean(count,
na.rm = TRUE),
by = c("Geneid",
"trt",
"time")]
dmu <- unique(dp1[, -c("Sample",
"count")])
head(dmu)
List of 1
$ axis.text.x:List of 11
..$ family : NULL
..$ face : NULL
..$ colour : NULL
..$ size : NULL
..$ hjust : num 1
..$ vjust : NULL
..$ angle : num 45
..$ lineheight : NULL
..$ margin : NULL
..$ debug : NULL
..$ inherit.blank: logi FALSE
..- attr(*, "class")= chr [1:2] "element_text" "element"
- attr(*, "class")= chr [1:2] "theme" "gg"
- attr(*, "complete")= logi FALSE
- attr(*, "validate")= logi TRUE

Did down-up-down trend persist?
dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$up.dn]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$up.dn]), ]
p1 <- ggplot(dp1.tmp,
aes(x = time,
y = count,
group = trt,
fill = trt)) +
facet_wrap(~ Geneid,
scale = "free_y") +
geom_point(position = position_dodge(0.5),
shape = 21,
size = 5,
color = "black") +
geom_line(data = dmu.tmp,
aes(x = time,
y = mu,
group = trt,
colour = trt),
position = position_dodge(0.5),
alpha = 0.5,
size = 2) +
scale_x_discrete("") +
scale_y_continuous("DESeq-Normalized Counts") +
scale_fill_discrete("Treatment")
print(p1)

List of 1
$ axis.text.x:List of 11
..$ family : NULL
..$ face : NULL
..$ colour : NULL
..$ size : NULL
..$ hjust : num 1
..$ vjust : NULL
..$ angle : num 45
..$ lineheight : NULL
..$ margin : NULL
..$ debug : NULL
..$ inherit.blank: logi FALSE
..- attr(*, "class")= chr [1:2] "element_text" "element"
- attr(*, "class")= chr [1:2] "theme" "gg"
- attr(*, "complete")= logi FALSE
- attr(*, "validate")= logi TRUE

Did up-down-up trend persist?
dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$dn.up]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$dn.up]), ]
p1 <- ggplot(dp1.tmp,
aes(x = time,
y = count,
group = trt,
fill = trt)) +
facet_wrap(~ Geneid,
scale = "free_y") +
geom_point(position = position_dodge(0.5),
shape = 21,
size = 5,
color = "black") +
geom_line(data = dmu.tmp,
aes(x = time,
y = mu,
group = trt,
colour = trt),
position = position_dodge(0.5),
alpha = 0.5,
size = 2) +
scale_x_discrete("") +
scale_y_continuous("DESeq-Normalized Counts") +
scale_fill_discrete("Treatment")
print(p1)

In many of these genes, UVB+SFN moved closer to UVB over time.
Heatmap for Week 2 differentially methylated genes
up.dn.w2 <- unique(as.character(dmu.w2$Geneid[dmu.w2$up.dn]))
dn.up.w2 <- unique(as.character(dmu.w2$Geneid[dmu.w2$dn.up]))
ll <- unique(c(up.dn.w2,
dn.up.w2))
# 36 genes
con_uvb_week2 <- data.table(Geneid = res_con_uvb_week2@rownames,
log2FoldChange = res_con_uvb_week2@listData$log2FoldChange)
sfn_uvb_week2 <- data.table(Geneid = res_sfn_uvb_week2@rownames,
log2FoldChange = -res_sfn_uvb_week2@listData$log2FoldChange)
t1 <- merge(con_uvb_week2[con_uvb_week2$Geneid %in% ll, ],
sfn_uvb_week2[sfn_uvb_week2$Geneid %in% ll, ],
by = "Geneid")
colnames(t1)[2:3] <- c("Control vs. UVB",
"UVB vs. SFN+UVB")
t1 <- t1[order(t1$`Control vs. UVB`,
decreasing = TRUE), ]
write.csv(t1,
file = "tmp/w2_sign_changes.csv",
row.names = FALSE)
ll <- melt.data.table(data = t1,
id.vars = 1,
measure.vars = 2:3,
variable.name = "Comparison",
value.name = "Gene Expression Diff")
ll$Comparison <- factor(ll$Comparison,
levels = c("Control vs. UVB",
"UVB vs. SFN+UVB"))
lvls <- ll[ll$Comparison == "Control vs. UVB", ]
ll$Geneid <- factor(ll$Geneid,
levels = lvls$Geneid[order(lvls$`Gene Expression Diff`)])
# Add dendrogram----
dt.dndr <- data.frame(t1[Geneid %in% levels(ll$Geneid), ])
rownames(dt.dndr) <- dt.dndr$Gene
dt.dndr <- dt.dndr[, -1]
# Compute distances between genes----
sampleDists <- dist(dt.dndr)
# Make dendrogram data----
dhc <- as.dendrogram(hclust(d = sampleDists),
horiz = TRUE)
ddata <- dendro_data(dhc,
type = "rectangle")
# Segment data----
dtp1 <- segment(ddata)
# Hitmap data----
dtp2 <- ll
dtp2$Geneid <- factor(dtp2$Geneid,
levels = ddata$labels$label)
offset.size <- 4
p1 <- ggplot(data = dtp2) +
coord_polar("y",
start = -0.3,
direction = -1) +
geom_tile(aes(x = as.numeric(Comparison),
y = Geneid,
fill = `Gene Expression Diff`),
color = "white") +
geom_text(data = dtp2[Comparison == "Control vs. UVB", ],
aes(x = rep(1.75,
nlevels(Geneid)),
y = Geneid,
angle = 90 + seq(from = 30,
to = 330,
length.out = nlevels(Geneid))[as.numeric(Geneid)] +
offset.size,
label = unique(Geneid)),
hjust = 0) +
geom_text(data = dtp2[Geneid == levels(dtp2$Geneid)[1], ],
aes(x = 1:nlevels(Comparison),
y = rep(-offset.size,
nlevels(Comparison)),
angle = 0,
label = levels(Comparison)),
hjust = 1,
size = 5) +
scale_fill_gradient2(low = "red",
high = "green",
mid = "grey",
midpoint = 0,
name = "") +
scale_y_discrete("",
expand = c(0, 0)) +
theme(plot.title = element_text(hjust = 0.5),
axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.background = element_blank(),
legend.position = "bottom",
legend.text = element_text(size = 15),
legend.direction = "horizontal",
legend.key.width = unit(1, "in"),
legend.key.height = unit(0.3, "in")) +
geom_segment(data = dtp1,
aes(x = -sqrt(y) + 0.5,
y = x,
xend = -sqrt(yend) + 0.5,
yend = xend),
size = 1)
tiff(filename = "tmp/skin_ubv_sfn_hitmap_with_phylo.tiff",
height = 8,
width = 8,
units = 'in',
res = 600,
compression = "lzw+p")
plot(p1)
graphics.off()
print(p1)

Venn Diagram, Week 2
# 1. Ctrl vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up) : 1546, 9%
# LFC < 0 (down) : 1537, 8.9%
# 23 genes down-up-down
# 2. SFN+UVB vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up) : 26, 0.15%
# LFC < 0 (down) : 35, 0.2%
# 13 gens up-down-up
p1 <- ggplot() +
geom_circle(aes(x0 = c(1, 2, 1, 2),
y0 = c(1, 1, 4, 4),
r = rep(1, 4),
color = factor(c(2, 1, 1, 2))),
size = 2) +
geom_text(aes(x = rep(c(0.5, 1.5, 2.5), 2),
y = rep(c(1, 4), each = 3),
label = format(c(26, 13, 35, 1546, 23, 1537),
big.mark = ","))) +
scale_color_manual(values = c("green", "red")) +
theme_void() +
theme(legend.position = "none")
tiff(filename = "tmp/skin_ubv_sfn_w2_venn.tiff",
height = 6,
width = 4,
units = 'in',
res = 600,
compression = "lzw+p")
plot(p1)
graphics.off()
print(p1)

Interactions terms
Tests if the effect of NOT treating with UVB vs. treating with UVB is different at Week 15 compared to Week 2:
res_int_con_uvb_week <- results(dds,
name = "time15w.trtCON",
alpha = 0.1)
res_int_con_uvb_week <- res_int_con_uvb_week[order(res_int_con_uvb_week$padj,
decreasing = FALSE),]
print(res_int_con_uvb_week)
summary(res_int_con_uvb_week)
# How many adjusted p-values were less than 0.05?
sum(res_int_con_uvb_week$padj < 0.1,
na.rm = TRUE)
# MA plot
print(plotMA(res_int_con_uvb_week,
main = "(Control vs. UVB) x TIme Interaction",
alpha = 0.9))
Tests if the effect of treating with UVB+SFN vs. treating with UVB is different at Week 15 compared to Week 2:
res_int_sfn_uvb_week <- results(dds,
name = "time15w.trtSFN",
alpha = 0.1)
res_int_sfn_uvb_week <- res_int_sfn_uvb_week[order(res_int_sfn_uvb_week$padj,
decreasing = FALSE),]
print(res_int_sfn_uvb_week)
summary(res_int_sfn_uvb_week)
# How many adjusted p-values were less than 0.05?
sum(res_int_sfn_uvb_week$padj < 0.1,
na.rm = TRUE)
# MA plot
print(plotMA(res_int_sfn_uvb_week))
# NOTE: same as
# res <- results(dds,
# alpha = 0.05)
# res <- res[order(res$padj, decreasing = FALSE),]
# res
NOTE: By default, the results(dds)* prints the results for the last level of the last term, i.e. here it was for for the interaction term SFN vs. UVB at Week 15 vs. Week 2.
Genes with both interactions being significant
lgene.con <- unique(res_int_con_uvb_week@rownames[res_int_con_uvb_week$padj < 0.1])
lgene.sfn <- unique(res_int_sfn_uvb_week@rownames[res_int_sfn_uvb_week$padj < 0.1])
lgene <- lgene.con[lgene.con %in% lgene.sfn]
lgene <- lgene[!is.na(lgene)]
lgene
Plot of DESeq-normalizedcounts of genes with smallest adjusted p-value for the interaction term:
# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene)) {
out <- plotCounts(dds,
gene = lgene[[i]],
intgroup = c("trt",
"time"),
returnData = TRUE)
dp1[[i]] <- data.table(Geneid = lgene[[i]],
Sample = rownames(out),
out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
levels = c("CON",
"UVB",
"SFN"))
dp1$time <- factor(dp1$time,
levels = c("02w",
"15w"),
labels = c("Week 2",
"Week 15"))
dp1$Geneid <- factor(dp1$Geneid,
levels = lgene)
dp1[, mu := mean(count,
na.rm = TRUE),
by = c("Geneid",
"trt",
"time")]
dmu <- unique(dp1[, -c("Sample",
"count")])
p1 <- ggplot(dp1,
aes(x = time,
y = count,
group = trt,
fill = trt)) +
facet_wrap(~ Geneid,
scale = "free_y") +
geom_point(position = position_dodge(0.5),
shape = 21,
size = 5,
color = "black") +
geom_line(data = dmu,
aes(x = time,
y = mu,
group = trt,
colour = trt),
position = position_dodge(0.5),
alpha = 0.5,
size = 2) +
scale_x_discrete("") +
scale_y_continuous("DESeq-Normalized Counts") +
scale_fill_discrete("Treatment")
print(p1)
Compare to the plot of TPM-normalizedcounts of genes with smallest adjusted p-value for the interaction term:
# Examine TPM values for the same genes
tmp <- tpm[Geneid %in% lgene, ]
tmp$Geneid <- factor(tmp$Geneid,
levels = lgene)
tmp <- melt.data.table(data = tmp,
id.vars = 1,
measure.vars = 3:ncol(tmp),
variable.name = "Sample",
value.name = "TPM")
tmp <- merge(dmeta,
tmp,
by = "Sample")
p1 <- ggplot(tmp,
aes(x = Week,
y = TPM,
fill = Treatment,
group = Treatment)) +
facet_wrap(~ Geneid,
scales = "free_y") +
geom_point(position = position_dodge(0.5),
shape = 21,
size = 5,
color = "black")+
scale_x_discrete("")
plot(p1)
LS0tDQp0aXRsZTogIlNraW4gVVZCIFNLSDEgbW91c2UgbW9kZWwgdHJlYXRlZCB3aXRoIFNGTiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KLS0tDQoNCiMgUGFydCAxOiBSTkENCmBgYHtyIGhlYWRlciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVycm9yID0gRkFMU0UsIHdhcm5pbmcgID1GQUxTRX0NCiMgaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpDQoNCnJlcXVpcmUoa25pdHIpDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKERUKQ0KcmVxdWlyZShERVNlcTIpDQpyZXF1aXJlKHJlYWR4bCkNCnJlcXVpcmUoQmlvY1BhcmFsbGVsKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKHRocmVlanMpDQpyZXF1aXJlKHNjYWxlcykNCnJlcXVpcmUoZ3JpZEV4dHJhKQ0KcmVxdWlyZShnZ3B1YnIpDQpyZXF1aXJlKGdnZGVuZHJvKQ0KcmVxdWlyZShnZ2ZvcmNlKQ0KDQojIE5PVEU6IG9uIERFU2VxMiBPdXRwdXQ6ICdiYXNlTWVhbicgaXMgdGhlIGF2ZXJhZ2Ugb2YgdGhlIG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzLCANCiMgZGl2aWRlZCBieSB0aGUgc2l6ZSBmYWN0b3JzLCB0YWtlbiBvdmVyIGFsbCBzYW1wbGVzIGluIHRoZSBERVNlcURhdGFTZXQNCmBgYA0KDQojIyBMb2FkIFJOQSBzYW1wbGVzDQpPdXQgb2YgMzAgc2FtcGxlcywgd2Ugc2VsZWN0ZWQgMTcgZm9yIHRoaXMgc3R1ZHkuIFRoZXNlIGFyZSB0aGUgbm9ybWFsIHRpc3N1ZSBzYW1wbGVzIGZvcm0gdGhlIGNvbnRyb2wsIHRoZSBVVkEgYW5kIHRoZSBVVkErU0ZOIHRyZWF0bWVudCBncm91cHMuIG5vcm1hbCB0aXNzdWUgc2FtcGxlcyBmcm9tIHRoZSBVVkJfVUEgZ3JvdXBzIGFzIHdlbGwgYXMgdHVtb3Igc2FtcGxlcyB3ZXJlIGV4Y2x1ZGVkIGZyb20gdGhpcyBhbmFseXNpcy4gQWRkaXRpb25hbGx5LCBvbmUgb2YgdGhlIGNvbnRyb2wgc2FtcGxlcyBhdCBXZWVrIDIgKGJhc2VsaW5lKSB3YXMgcmVtb3ZlZCBhZnRlciBvdXRsaWVyIGFuYWx5c2lzLiAgICANCjcsMjE5IGdlbmVzIHdpdGggemVybyBjb3VudHMgaW4gPiA4MCUgKD4gMTMgb3V0IG9mIDE4KSBvZiBzYW1wbGVzIHdlcmUgcmVtb3ZlZC4gMTcsMjAyIG91dCBvZiAyNCw0MjEgZ2VuZXMgd2VyZSBsZWZ0LiANCiAgICAgICAgIA0KYGBge3IgZGF0YV9ybmEsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojIExvYWQgZGF0YS0tLS0NCmR0MCA8LSBmcmVhZCgiZGF0YS9yZW55aV9kZWR1cF9ybmFzZXFfZGF0YS9mZWF0dXJlc2NvdW50c191dmItc2tpbl9kZWR1cF9yZW55aV8yLTktMjAxOC5jc3YiLA0KICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQojIFJlbW92ZSB1bnVzZWQgY29sdW1ucy0tLS0NCmR0MSA8LSBkdDBbLCBjKDEsIDY6bmNvbChkdDApKSwgd2l0aCA9IEZBTFNFXQ0KDQpjbmFtZXMgPC0gY29sbmFtZXMoZHQxKVstYygxOjIpXQ0KY25hbWVzIDwtIGdzdWIoeCA9IGNuYW1lcywNCiAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLmRlZHVwLmJhbSIsDQogICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQ0KY29sbmFtZXMoZHQxKVstYygxOjIpXSA8LSBjbmFtZXMNCg0KIyBBVFRFTlRJT04hIEluIHRoaXMgYW5hbHlzaXMsIHdlIHdpbGwgb25seSBleGFtaW5lIGNvbnRyb2xzIGFuZCBTRk4NCiMgQWxzbywgcmVtb3ZlZCBjYW5jZXIgY2VsbCBzYW1wbGVzDQp0bmFtZXMgPC0gc3Vic3RyKHggPSBjb2xuYW1lcyhkdDEpLCANCiAgICAgICAgICAgICAgICAgc3RhcnQgPSAzLA0KICAgICAgICAgICAgICAgICBzdG9wID0gMykNCg0KZ25hbWVzIDwtIHN1YnN0cih4ID0gY29sbmFtZXMoZHQxKSwgDQogICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQoNCmR0MSA8LSBkdDFbLCBnbmFtZXMgJWluJSBjKCJpZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAidGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iICkgJg0KICAgICAgICAgICAgIHRuYW1lcyAhPSAidCIsDQogICAgICAgICAgIHdpdGggPSBGQUxTRV0NCiMgMTggc2FtcGxlcyBsZWZ0DQoNCiMgUmVtb3ZlIHNhbXBsZSAnMDJ3X0NPTl8xJyBhcyBhbiBvdXRsaWVyDQojIFNlZSAnc2tpbl91dmJfc2ZuX2V4Y2x1ZGVfY29uMncxX3YxJyBmb3IgZGV0YWlscw0KZHQxIDwtIGR0MVssIGNvbG5hbWVzKGR0MSkgIT0gIjAyd19DT05fMSIsIHdpdGggPSBGQUxTRV0NCg0KIyBSZW1vdmUgZ2VuZXMgd2l0aCB6ZXJvIGNvdW50cyBpbiA+IDgwJSAoPiAxMyBvdXQgb2YgMTcpIG9mIHNhbXBsZXMNCnRtcCA8LSBkdDFbLCAtYygxOjIpXSA9PSAwDQp0bXAgPC0gcm93U3Vtcyh0bXApID4gMTMNCnN1bSh0bXApDQoNCmR0MSA8LSBkcm9wbGV2ZWxzKGR0MVshdG1wLCBdKQ0KbnJvdyhkdDEpDQojIDE3LDIwMiBvdXQgb2YgMjQsNDIxIGdlbmVzIGxlZnQNCg0KZGF0YXRhYmxlKGhlYWQoZHQxLCAxMCksDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApLA0KICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgMTogZmlyc3QgMTAgcm93cyBvZiB0aGUgY291bnQgdGFibGUiKQ0KYGBgDQoNCiMjIFRyYW5zY3JpcHRzIHBlciBraWxvYmFzZSBtaWxsaW9uIChUUE0pIG5vcm1hbGl6YXRpb24NCk5leHQsIHdlIG5vcmFtaXplZCB0aGUgY291bnRzLiBUbyBjb252ZXJ0IG51bWJlciBvZiBoaXRzIHRvICB0aGUgcmVsYXRpdmUgYWJ1bmRhbmUgb2YgZ2VuZXMgaW4gZWFjaCBzYW1wbGUsIHdlIHVzZWQgKioqdHJhbnNjcmlwdHMgcGVyIGtpbG9iYXNlIG1pbGxpb24gKFRQTSkqKiogbm9ybWFsaXphdGlvbiwgd2hpY2ggaXMgYXMgZm9sbG93aW5nIGZvciB0aGUgai10aCBzYW1wbGU6ICAgICAgIA0KMS4gbm9ybWlsaXplIGZvciBnZW5lIGxlbmd0aDogYVtpLCBqXSA9IDEsMDAwKmNvdW50W2ksIGpdL2dlbmVbaSwgal0gbGVuZ3RoKGJwKSAgICAgDQoyLiBub3JtYWxpemUgZm9yIHNlcSBkZXB0aCAoaS5lLiB0b3RhbCBjb3VudCk6IGEoaSwgaikvc3VtKGFbLCBqXSkgICAgIA0KMy4gbXVsdGlwbHkgYnkgb25lIG1pbGxpb24gICAgIA0KQSB2ZXJ5IGdvb2QgY29tcGFyaXNvbiBvZiBub3JtYWxpemF0aW9uIHRlY2huaXF1ZXMgY2FuIGJlIGZvdW5kIGF0IHRoZSBmb2xsb3dpbmcgdmlkZW86ICAgIA0KW1JQS00sIEZQS00gYW5kIFRQTSwgY2xlYXJseSBleHBsYWluZWRdKGh0dHBzOi8vd3d3LnJuYS1zZXFibG9nLmNvbS9ycGttLWZwa20tYW5kLXRwbS1jbGVhcmx5LWV4cGxhaW5lZC8pDQogICAgIA0KQWZ0ZXIgdGhlIG5vcm1hbGl6YXRpb24sIGVhY2ggc2FtcGxlJ3MgdG90YWwgaXMgMU06DQogICAgIA0KYGBge3IgdHBtLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KIyBOb3JtYWxpemUgY291bnRzIHRvIFRQTQ0KdG1wIDwtIDEwMDAqZHQxWywgMzpuY29sKGR0MSldL2R0MSRMZW5ndGgNCnRwbSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGR0MSRHZW5laWQsDQogICAgICAgICAgICAgICAgICBMZW5ndGggPSBkdDEkTGVuZ3RoLA0KICAgICAgICAgICAgICAgICAgYXBwbHkodG1wLA0KICAgICAgICAgICAgICAgICAgICAgICAgMiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGEpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgMTBeNiooYS9zdW0oYSkpDQogICAgICAgICAgICAgICAgICAgICAgICB9KSkNCmNvbFN1bXModHBtWywgLWMoMToyKV0pDQoNCmZvcm1hdFJvdW5kKGRhdGF0YWJsZShoZWFkKHRwbSwgMTApLA0KICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSwNCiAgICAgICAgICAgICAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIDI6IHRyYW5zY3JpcHRzIHBlciBraWxvYmFzZSBtaWxsaW9uIChUUE0pIG5vcm1hbGl6ZWQgY291bnRzIiksDQogICAgICAgICAgICBjb2x1bW5zID0gMzpuY29sKHRwbSksDQogICAgICAgICAgICBkaWdpdHMgPSAyKQ0KDQojIFRvdGFsIFRQTQ0KdG90YWwgPC0gcm93U3Vtcyh0cG1bLCAzOm5jb2wodHBtKV0pDQoNCiMgU29ydCBnZW5lcyBieSByZWxhdGl2ZSBhYnVuZGFuY3kNCnRwbSRHZW5laWQgPC0gZmFjdG9yKHRwbSRHZW5laWQgLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdHBtJEdlbmVpZFtvcmRlcih0b3RhbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKV0pDQpgYGANCg0KIyBUb3AgMTAwIG1vc3QgYWJ1bmRhbnQgUk5BIG1vbGVjdWxlcw0KYGBge3IgbW9zdF9hYnVuZGFudH0NCiMgU2VwYXJhdGUgdG9wIDEwMCBhYnVuZGFudCBnZW5lcw0KdG1wIDwtIGRyb3BsZXZlbHModHBtW0dlbmVpZCAlaW4lIGxldmVscyh0cG0kR2VuZWlkKVsobnJvdyh0cG0pIC0gOTkpOm5yb3codHBtKV1dKQ0KDQp0bXAgPC0gbWVsdC5kYXRhLnRhYmxlKGRhdGEgPSB0bXAsDQogICAgICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSAxOjIsDQogICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IDM6bmNvbCh0bXApLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiVFBNIikNCg0KdG1wJFdlZWsgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCnRtcCRXZWVrIDwtIGZhY3Rvcih0bXAkV2VlaywNCiAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUodG1wJFdlZWspKQ0KDQoNCnRtcCRUcmVhdG1lbnQgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQp0bXAkVHJlYXRtZW50IDwtIGZhY3Rvcih0bXAkVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQoNCnRtcCRSZXBsaWNhIDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDksDQogICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDkpDQp0bXAkUmVwbGljYSA8LSBmYWN0b3IodG1wJFJlcGxpY2EsDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMDoxKQ0KDQojIFBsb3QgdG9wIDEwMCBhYnVuZGFudCBnZW5lcw0KcDIgPC0gZ2dwbG90KHRtcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFRQTSwNCiAgICAgICAgICAgICAgICAgeSA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSBXZWVrKSkgKw0KICAjIGZhY2V0X3dyYXAofiBTZXgsIG5yb3cgPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKQ0KZ2dwbG90bHkocDIpDQpgYGANCg0KIyBCb3R0b20gMTAwIGxlYXN0IGFidW5kYW50IFJOQSBtb2xlY3VsZXMNCmBgYHtyIGxlYXN0X2FidW5kYW50fQ0KdG1wIDwtIGRyb3BsZXZlbHModHBtW0dlbmVpZCAlaW4lIGxldmVscyh0cG0kR2VuZWlkKVsxOjEwMF1dKQ0KDQp0bXAgPC0gbWVsdC5kYXRhLnRhYmxlKGRhdGEgPSB0bXAsDQogICAgICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSAxOjIsDQogICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IDM6bmNvbCh0bXApLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiVFBNIikNCg0KdG1wJFdlZWsgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCnRtcCRXZWVrIDwtIGZhY3Rvcih0bXAkV2VlaywNCiAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUodG1wJFdlZWspKQ0KDQoNCnRtcCRUcmVhdG1lbnQgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQp0bXAkVHJlYXRtZW50IDwtIGZhY3Rvcih0bXAkVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQoNCnRtcCRSZXBsaWNhIDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDksDQogICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDkpDQp0bXAkUmVwbGljYSA8LSBmYWN0b3IodG1wJFJlcGxpY2EsDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMDoxKQ0KDQojIFBsb3QgdG9wIDEwMCBhYnVuZGFudCBnZW5lcw0KcDMgPC0gZ2dwbG90KHRtcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFRQTSwNCiAgICAgICAgICAgICAgICAgeSA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSBXZWVrKSkgKw0KICAjIGZhY2V0X3dyYXAofiBTZXgsIG5yb3cgPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKQ0KZ2dwbG90bHkocDMpDQpgYGANCg0KIyBNZXRhIGRhdGENCmBgYHtyIG1ldGF9DQpkbWV0YSA8LSBkYXRhLnRhYmxlKFNhbXBsZSA9IGNvbG5hbWVzKGR0MSlbLWMoMToyKV0pDQoNCmRtZXRhJHRpbWUgPC0gc3Vic3RyKHggPSBkbWV0YSRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDEsDQogICAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCmRtZXRhJHRpbWUgPC0gZmFjdG9yKGRtZXRhJHRpbWUsDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCIwMnciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1dyIpKQ0KZG1ldGEkV2VlayA8LSBmYWN0b3IoZG1ldGEkdGltZSwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjV3IiksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXZWVrIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDI1IikpDQoNCmRtZXRhJHRydCA8LSBzdWJzdHIoeCA9IGRtZXRhJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICAgICBzdG9wID0gNykNCmRtZXRhJHRydCA8LSBmYWN0b3IoZG1ldGEkdHJ0LA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQpkbWV0YSRUcmVhdG1lbnQgPC0gZmFjdG9yKGRtZXRhJHRydCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJOZWdhdGl2ZSBDb250cm9sIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zaXRpdmUgQ29udHJvbCAoVVZCKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN1bGZvcmFwaGFuZSAoU0ZOKSIpKQ0KDQpkbWV0YSRSZXBsaWNhIDwtIHN1YnN0cih4ID0gZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDkpDQpkbWV0YSRSZXBsaWNhIDwtIGZhY3RvcihkbWV0YSRSZXBsaWNhLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMDoxKQ0KDQpkYXRhdGFibGUoZG1ldGEsDQogICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IG5yb3coZG1ldGEpKSkNCmBgYA0KDQojIFBDQSBvZiBUUE0NCk5PVEU6IHRoZSBkaXN0cmlidXRpb25zIGFyZSBza2V3ZWQuIFRvIG1ha2UgdGhlbSBzeW1tZXRyaWMsIGxvZyB0cmFuc2Zvcm1hdGlvbiBpcyBvZnRlbiBhcHBsaWVkLiBIb3dldmVyLCB0aGVyZSBpcyBhbiBpc3N1ZSBvZiB6ZXJvcy4gSW4gdGhpcyBpbnN0YW5jZSwgd2UgYWRkZWQgYSBzbWFsbCB2YWx1ZXMgKioqbGFtYmRhW2ldKioqIGVxdWFsIHRvIDEvMTAgb2YgdGhlIHNtYWxsZXN0IG5vbi16ZXJvIHZhbHVlIG9mICppKi10aCBnZW5lLiANCmBgYHtyIHBjYX0NCmRtLnRwbSA8LSBhcy5tYXRyaXgodHBtWywgLWMoMToyKSwgd2l0aCA9IEZBTFNFXSkNCnJvd25hbWVzKGRtLnRwbSkgPC0gdHBtJEdlbmVpZA0KDQojICMgUmVtb3ZlIDAyd19DT05fMSBzYW1wbGUgYW5kIHJlZG8gUENBDQojIGRtLnRwbSA8LSBkbS50cG1bLCBjb2xuYW1lcyhkbS50cG0pICE9ICIwMndfQ09OXzEiXQ0KIyBkbWV0YSA8LSBkbWV0YVtkbWV0YSRTYW1wbGUgIT0gIjAyd19DT05fMSIsIF0NCg0KIyBBZGQgbGFtYmRhcyB0byBhbGwgdmFsdWVzLCB0aGVuIHRha2UgYSBsb2cNCmRtLmx0cG0gPC0gdChhcHBseShYID0gZG0udHBtLA0KICAgICAgICAgICAgICAgICAgICAgIE1BUkdJTiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oYSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhIDwtIG1pbihhW2EgPiAwXSkvMTANCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZyhhICsgbGFtYmRhKQ0KICAgICAgICAgICAgICAgICAgICAgIH0pKQ0KDQojIFBDQS0tLS0NCm0xIDwtIHByY29tcCh0KGRtLmx0cG0pLA0KICAgICAgICAgICAgIGNlbnRlciA9IFRSVUUsDQogICAgICAgICAgICAgc2NhbGUuID0gVFJVRSkNCg0KczEgPC0gc3VtbWFyeShtMSkNCnMxDQpgYGANCg0KIyBQYXJldG8gY2hhcnQgb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IHByaW5jaXBhbCBjb21wb25lbnRzDQpgYGB7ciBwY2FfdmFyX3Bsb3R9DQppbXAgPC0gZGF0YS50YWJsZShQQyA9IGNvbG5hbWVzKHMxJGltcG9ydGFuY2UpLA0KICAgICAgICAgICAgICAgICAgVmFyaWFuY2UgPSAxMDAqczEkaW1wb3J0YW5jZVsyLCBdLA0KICAgICAgICAgICAgICAgICAgQ3VtdWxhdGl2ZSA9IDEwMCpzMSRpbXBvcnRhbmNlWzMsIF0pDQppbXAkUEMgPC0gZmFjdG9yKGltcCRQQywNCiAgICAgICAgICAgICAgICAgbGV2ZWxzID0gaW1wJFBDKQ0KcDEgPC0gZ2dwbG90KGltcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDLA0KICAgICAgICAgICAgICAgICB5ID0gVmFyaWFuY2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLA0KICAgICAgICAgICBmaWxsID0gImdyZXkiLA0KICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gcmVzY2FsZShDdW11bGF0aXZlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYyhtaW4oQ3VtdWxhdGl2ZSkqMzAvMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzMCkpLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gcmVwKDEsIG5yb3coaW1wKSkpKSArDQogIGdlb21fcG9pbnQoYWVzKHkgPSByZXNjYWxlKEN1bXVsYXRpdmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYyhtaW4oQ3VtdWxhdGl2ZSkqMzAvMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMzApKSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCIlIFZhcmlhbmNlIEV4cGxhaW5lZCIsDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMzAsIGJ5ID0gNSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwYXN0ZShzZXEoMCwgMzAsIGJ5ID0gNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIiksDQogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKHRyYW5zID0gfi4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBDdW11bGF0aXZlIFZhcmlhbmNlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDMwLCBsZW5ndGgub3V0ID0gNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBhc3RlKHNlcSgwLCAxMDAsIGxlbmd0aC5vdXQgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIikpKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCg0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvcGNhX3BhcmV0by50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA4LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcHJpbnQocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIHBhaXJ3aXNlDQpgYGB7ciBwY2FfcGxvdHN9DQojIEJpcGxvdCB3aGlsZSBrZWVwIG9ubHkgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyAoSmF2aWVyKS0tLS0NCiMgU2VsZWN0IFBDLXMgdG8gcGxpb3QgKFBDMSAmIFBDMikNCmNob2ljZXMgPC0gYygxOjMpDQoNCiMgU2NvcmVzLCBpLmUuIHBvaW50cyAoZGYudSkNCmR0LnNjciA8LSBkYXRhLnRhYmxlKG0xJHhbLCBjaG9pY2VzXSkNCiMgQWRkIGdyb3VwaW5nIHZhcmlhYmxlcw0KZHQuc2NyJHRydCA8LSBkbWV0YSR0cnQNCmR0LnNjciR0aW1lIDwtIGRtZXRhJHRpbWUNCmR0LnNjciRzYW1wbGUgPC0gZG1ldGEkU2FtcGxlDQoNCiMgTG9hZGluZ3MsIGkuZS4gYXJyb3dzIChkZi52KQ0KZHQucm90IDwtIGFzLmRhdGEuZnJhbWUobTEkcm90YXRpb25bLCBjaG9pY2VzXSkNCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkNCmR0LnJvdCA8LSBkYXRhLnRhYmxlKGR0LnJvdCkNCg0KIyBBeGlzIGxhYmVscw0KdS5heGlzLmxhYnMgPC0gcGFzdGUoY29sbmFtZXMoZHQucm90KVtjaG9pY2VzXSwgDQogICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCcoJTAuMWYlJSBleHBsYWluZWQgdmFyLiknLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKm0xJHNkZXZbY2hvaWNlc11eMi9zdW0obTEkc2Rldl4yKSkpDQoNCnAxIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMyLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDEpDQoNCnAyIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMzLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbM10pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDIpDQoNCnAzIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMyLA0KICAgICAgICAgICAgICAgICB5ID0gUEMzLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1syXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbM10pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDMpDQoNCiMgTGVnZW5kIG9ubHkNCnRtcCA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMSwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMiwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoIlRyZWF0bWVudCIpICsNCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUoIldlZWsiKQ0KcDQgPC0gYXNfZ2dwbG90KGdldF9sZWdlbmQodG1wKSkNCg0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvcGNhLnRpZmYiLA0KICAgICBoZWlnaHQgPSA3LA0KICAgICB3aWR0aCA9IDksDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgcDQsIA0KICAgICAgICAgICAgIG5yb3cgPSAyKQ0KZ3JhcGhpY3Mub2ZmKCkNCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIDNEDQpgYGB7ciBwY2FfM2QsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9DQpzY2F0dGVycGxvdDNqcyh4ID0gZHQuc2NyJFBDMSwgDQogICAgICAgICAgICAgICB5ID0gZHQuc2NyJFBDMiwgDQogICAgICAgICAgICAgICB6ID0gZHQuc2NyJFBDMywgDQogICAgICAgICAgICAgICBjb2xvciA9IGFzLm51bWVyaWMoZHQuc2NyJHRydCksDQogICAgICAgICAgICAgICByZW5kZXJlciA9ICJhdXRvIiwNCiAgICAgICAgICAgICAgIHBjaCA9IGR0LnNjciRzYW1wbGUsDQogICAgICAgICAgICAgICBzaXplID0gMC4xKQ0KYGBgDQoNCiMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgKERFU2VxMiBwaXBlbGluZSkNClNvdXJjZXM6ICAgIA0KMS4gW0FuYWx5emluZyBSTkEtc2VxIGRhdGEgd2l0aCBERVNlcTI6SW50ZXJhY3Rpb25zXShodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL2RldmVsL2Jpb2MvdmlnbmV0dGVzL0RFU2VxMi9pbnN0L2RvYy9ERVNlcTIuaHRtbCNpbnRlcmFjdGlvbnMpICAgICANCjIuIFtCaW9jb25kdWN0b3IgUXVlc3Rpb246IERFU2VxMiB0aW1lIHNlcmllcyBhbmFseXNpc10oaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC85NzQzMC8pICAgICAgDQpXZSBhcmUgdGVzdGluZyBhIG1vZGVsIHdpdGggdGltZSp0cmVhdG1lbnQgaW50ZXJhY3Rpb24uIFRoZSBpZGVhIGhlcmUgaXMgdG8gZmluZCBnZW5lcyB3aXRoIHNpZ25pZmljYW50IGludGVyYWN0aW9uIHRlcm0uIFRoYXQgd291bGQgc3VnZ2VzdCB0aGF0IHRoZSBnZW5lIGV4cHJlc3Npb25kaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB0cmVhdG1lbnRzIGRlcGVuZGVkIG9uIHRpbWUuIFRIZXJlIGFyZSBzZXZlcmFsIHBvc3NpYmxlIHNjZW5hcmlvczogICAgDQphLiBObyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG5lZ2F0aXZlIGNvbnRyb2wgYW5kIHRoZSBwb3NpdGl2ZSBjb250cm9sIGdyb3VwcyBhdCBiYXNlbGluZSwgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBhdCB0aGUgbGF0ZXIgdGltZSBwb2ludC4gVGhpcyB3aWxsIHNob3cgdGhlIGVmZmVjdCBvZiB0aGUgZGlzZWFzZSAoVVZCIHJhZGlhdGlvbiwgaW4gdGhpcyBjYXNlKS4gICAgIA0KYi4gU2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjb250cm9sIGdyb3VwcyBhdCBiYXNlbGluZSwgbm8gZGlmZmVyZW5jZSBhdCB0aGUgbGF0ZXIgdGltZSBwb2ludC4gU2FtZSBhcyAoYSkgYWJvdmUuICAgICANCmMuIERpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHBvc2l0aXZlIGNvbnRyb2wgYW5kIHRoZSBTRk4tdHJlYXRlZCBncm91cHMuIEhlcmUsIHdlIGFyZSBpbnRlcmVzdGVkIGluIHRoZSByZXZlcnNhbCBvZiBVVkIgZWZmZWN0LiBBZ2FpbiwgdGhlIGludGVyYWN0aW9uIHRlcm0gd2lsbCBuZWVkIHRvIGJlIHNpZ25pZmljYW50IGZvciB0aGUgcmVhc29ucyBkZXNjcmliZWQgYWJvdmUuICAgICAgDQoNCmBgYHtyIGRlc2VxMn0NCiMgUmVsZXZlbDogbWFrZSBhbGwgY29tcGFyaXNvbnMgd2l0aCB0aGUgcG9zaXRpdmUgY29udHJvbCAoVVZCKQ0KZG1ldGEkdHJ0IDwtIGZhY3RvcihkbWV0YSR0cnQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KDQpkdG08LSBhcy5tYXRyaXgoZHQxWywgZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICB3aXRoID0gRkFMU0VdKQ0Kcm93bmFtZXMoZHRtKSA8LSBkdDEkR2VuZWlkDQoNCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGR0bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gZG1ldGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IHRpbWUgKyB0cnQgKyB0aW1lOnRydCkNCiMgSWYgYWxsIHNhbXBsZXMgY29udGFpbiB6ZXJvcywgZ2VvbWV0cmljIG1lYW5zIGNhbm5vdCBiZQ0KIyBlc3RpbWF0ZWQuIENoYW5nZSBkZWZhdWx0ICd0eXBlID0gInJhdGlvIicgdG8gJ3R5cGUgPSAicG9zY291bnRzIicuDQojIFR5cGUgJz9ERVNlcTI6OmVzdGltYXRlU2l6ZUZhY3RvcnMnIGZvciBtb3JlIGRldGFpbHMuDQpkZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhvYmplY3QgPSBkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBvc2NvdW50cyIpDQoNCiMgUnVuIERFU2VxLS0tLQ0KZGRzIDwtIERFU2VxKG9iamVjdCA9IGRkcywNCiAgICAgICAgICAgICAjIHRlc3QgPSAiTFJUIiwNCiAgICAgICAgICAgICAjIHJlZHVjZWQgPSB+IHRpbWUgKyB0cnQsDQogICAgICAgICAgICAgZml0VHlwZSA9ICJsb2NhbCIsDQogICAgICAgICAgICAgc2ZUeXBlID0gInJhdGlvIiwNCiAgICAgICAgICAgICBwYXJhbGxlbCA9IEZBTFNFKQ0KDQojIE5PVEUgKGZyb20gREVTZXEgaGVscCBmaWxlLCBzZWN0aW9uIFZhbHVlKToNCiMgQSBERVNlcURhdGFTZXQgb2JqZWN0IHdpdGggcmVzdWx0cyBzdG9yZWQgYXMgbWV0YWRhdGEgY29sdW1ucy4gDQojIFRoZXNlIHJlc3VsdHMgc2hvdWxkIGFjY2Vzc2VkIGJ5IGNhbGxpbmcgdGhlIHJlc3VsdHMgZnVuY3Rpb24uIA0KIyBCeSBkZWZhdWx0IHRoaXMgd2lsbCByZXR1cm4gdGhlIGxvZzIgZm9sZCBjaGFuZ2VzIGFuZCBwLXZhbHVlcw0KIyBmb3IgdGhlIGxhc3QgdmFyaWFibGUgaW4gdGhlIGRlc2lnbiBmb3JtdWxhLiANCiMgU2VlIHJlc3VsdHMgZm9yIGhvdyB0byBhY2Nlc3MgcmVzdWx0cyBmb3Igb3RoZXIgdmFyaWFibGVzLg0KIyBJbiB0aGlzIGNhc2UsIHRoZSBsYXN0IHRlcm0gaXMgdGhlIGludGVyYWN0aW9uIHRlcm0gdHJ0OnRpbWUNCg0KIyBOT1RFOiANCiMgTGlrZWxpaG9vZCByYXRpbyB0ZXN0IChMUlQpIChjaGktc3F1YXJlZCB0ZXN0KSBmb3IgR0xNIHdpbGwgb25seSByZXR1cm4gDQojIHRoZSByZXN1bHRzIGZvciB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBmdWxsIGFuZCB0aGUgcmVkdWNlZCBtb2RlbA0KDQpyZXN1bHRzTmFtZXMoZGRzKQ0KDQojIE1vZGVsIG1hdHJpeA0KbW0xIDwtIG1vZGVsLm1hdHJpeCh+IHRpbWUgKyB0cnQgKyB0aW1lOnRydCwgZG1ldGEpDQptbTENCmBgYA0KDQojIFJlc3VsdHMNCiMjIEVmZmVjdCBvZiBVVkIgYXQgV2VlayAyDQpgYGB7ciBkZXNlcTJfcmVzdWx0c193ZWVrMl9jb25fdXZifQ0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygwLDAsMCwxLDAsMCwwLDAsMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzX2Nvbl91dmJfd2VlazJbb3JkZXIocmVzX2Nvbl91dmJfd2VlazIkcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0Kc3VtbWFyeShyZXNfY29uX3V2Yl93ZWVrMikNCg0KIyBIb3cgbWFueSBhZGp1c3RlZCBwLXZhbHVlcyB3ZXJlIGxlc3MgdGhhbiAwLjA1Pw0Kc3VtKHJlc19jb25fdXZiX3dlZWsyJHBhZGogPCAwLjEsIA0KICAgIG5hLnJtID0gVFJVRSkNCg0KIyBNQSBwbG90DQojIFNhdmUgZm9yIHB1YmxpY2F0aW9uDQp0aWZmKGZpbGVuYW1lID0gInRtcC9tYV93Ml9jb25fdXZiLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDcsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwbG90TUEocmVzX2Nvbl91dmJfd2VlazIsDQogICAgICAgICAgICAgbWFpbiA9ICJDb250cm9sIHZzLiBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkNCmdyYXBoaWNzLm9mZigpDQoNCnBsb3RNQShyZXNfY29uX3V2Yl93ZWVrMiwNCiAgICAgICAgICAgICBtYWluID0gIkNvbnRyb2wgdnMuIFVWQiBhdCBXZWVrIDIiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KQ0KYGBgDQoNCiMjIFByb3RlY3RpdmUgZWZmZWN0IG9mIFNGTiBhdCBXZWVrIDINCmBgYHtyIGRlc2VxMl9yZXN1bHRzX3dlZWsyX3Nmbl91dmJ9DQpyZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXN1bHRzKGRkcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKDAsMCwwLDAsMSwwLDAsMCwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXNfc2ZuX3V2Yl93ZWVrMltvcmRlcihyZXNfc2ZuX3V2Yl93ZWVrMiRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpzdW1tYXJ5KHJlc19zZm5fdXZiX3dlZWsyKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX3Nmbl91dmJfd2VlazIkcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCiMgU2F2ZSBmb3IgcHVibGljYXRpb24NCnRpZmYoZmlsZW5hbWUgPSAidG1wL21hX3cyX3Nmbl91dmIudGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gNywNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHBsb3RNQShyZXNfc2ZuX3V2Yl93ZWVrMiwNCiAgICAgICAgICAgICBtYWluID0gIlVWQitTRk4gdnMgVVZCIGF0IFdlZWsgMiIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocGxvdE1BKHJlc19zZm5fdXZiX3dlZWsyLA0KICAgICAgICAgICAgIG1haW4gPSAiVVZCK1NGTiB2cyBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkpDQpgYGANCg0KIyMgR2VuZXMgdGhhdCB3ZXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWF0ZWQgYXQgYm90aCB0aW1lcG9pbnRzDQpgYGB7ciBzaWduX3cyfQ0KbGdlbmUudzIuY29uIDwtIHVuaXF1ZShyZXNfY29uX3V2Yl93ZWVrMkByb3duYW1lc1tyZXNfY29uX3V2Yl93ZWVrMiRwYWRqIDwgMC4xXSkNCmxnZW5lLncyLnNmbiA8LSB1bmlxdWUocmVzX3Nmbl91dmJfd2VlazJAcm93bmFtZXNbcmVzX3Nmbl91dmJfd2VlazIkcGFkaiA8IDAuMV0pDQpsZ2VuZS53MiA8LSBsZ2VuZS53Mi5jb25bbGdlbmUudzIuY29uICVpbiUgbGdlbmUudzIuc2ZuXQ0KbGdlbmUudzIgPC0gbGdlbmUudzIgWyFpcy5uYShsZ2VuZS53MiApXQ0KbGdlbmUudzINCmBgYA0KDQpQbG90IG9mIERFU2VxLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgc2lnbmlmaWNhbnQgaW4gYm90aCBjb21wYXJpc29ucyBhdCBXZWVrIDI6ICAgDQoNCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtfQ0KIyBHZXQgdGhlIERFU2VxLW5vcm1hbGl6ZSBjb3VudHMNCmRwMSA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOmxlbmd0aChsZ2VuZS53MikpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lLncyW1tpXV0sDQogICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygidHJ0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiksDQogICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUUlVFKQ0KICBkcDFbW2ldXSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGxnZW5lLncyW1tpXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlID0gcm93bmFtZXMob3V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvdXQpDQp9DQpkcDEgPC0gcmJpbmRsaXN0KGRwMSkNCmRwMSR0cnQgPC0gZmFjdG9yKGRwMSR0cnQsDQogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KZHAxJHRpbWUgPC0gZmFjdG9yKGRwMSR0aW1lLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNXciKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXZWVrIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgMTUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgMjUiKSkNCmRwMSRHZW5laWQgPC0gZmFjdG9yKGRwMSRHZW5laWQsDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBsZ2VuZS53MikNCmRwMVssIG11IDo9IG1lYW4oY291bnQsDQogICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgYnkgPSBjKCJHZW5laWQiLA0KICAgICAgICAgICAidHJ0IiwNCiAgICAgICAgICAgInRpbWUiKV0NCmRtdSA8LSB1bmlxdWUoZHAxWywgLWMoIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICJjb3VudCIpXSkNCmhlYWQoZG11KQ0KYGBgDQoNCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtX3cyX3VwX2RuLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9DQpkbXUudzIgPC0gZG11W3RpbWUgPT0gIldlZWsgMiIsIF0NCmRtdS53MlssIHVwLmRuIDo9IChtdVt0cnQgPT0gIlVWQiJdID4gbXVbdHJ0ID09ICJDT04iXSkgJg0KICAgICAgICAgICAgICAgKG11W3RydCA9PSAiVVZCIl0gPiBtdVt0cnQgPT0gIlNGTiJdKSwNCiAgICAgICBieSA9IEdlbmVpZF0NCnAxIDwtIGdncGxvdChkbXUudzJbdXAuZG4gPT0gVFJVRSwgXSwNCiAgICAgICAgICAgICBhZXMoeCA9IHRydCwNCiAgICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgICBncm91cCA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgICAgICAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogICAgICAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsNCiAgICAgICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkRpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcyBhdCBXZWVrIDIiKSArDQogICAgICAgIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpICsNCiAgICAgICAgZ2d0aXRsZSgiR2VuZXMgVXByZWd1bGF0ZWQgYnkgVVZCIikNCnRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQ0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC93Ml91cF9kbi50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA4LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDMwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcHJpbnQocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIyBEaWQgZG93bi11cC1kb3duIHRyZW5kIHBlcnNpc3Q/DQpgYGB7ciBkZXNlcTJfdzJzaWduX2Rlc2Vxbm9ybV9wbG90X2FsbF91cF9kbiwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0NCmRwMS50bXAgPC0gZHAxW2RwMSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncyJEdlbmVpZFtkbXUudzIkdXAuZG5dKSwgXQ0KZG11LnRtcCA8LSBkbXVbZG11JEdlbmVpZCAlaW4lIHVuaXF1ZShkbXUudzIkR2VuZWlkW2RtdS53MiR1cC5kbl0pLCBdDQpwMSA8LSBnZ3Bsb3QoZHAxLnRtcCwNCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgIHkgPSBjb3VudCwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSB0cnQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSB0cnQpKSArDQogIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV95IikgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgIHNpemUgPSA1LA0KICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRtdS50bXAsDQogICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgIGNvbG91ciA9IHRydCksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICBhbHBoYSA9IDAuNSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJERVNlcS1Ob3JtYWxpemVkIENvdW50cyIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikNCnByaW50KHAxKQ0KYGBgDQoNCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtX3cyX2RuX3VwLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9DQpkbXUudzJbLCBkbi51cCA6PSAobXVbdHJ0ID09ICJVVkIiXSA8IG11W3RydCA9PSAiQ09OIl0pICYNCiAgICAgICAgICAgICAgIChtdVt0cnQgPT0gIlVWQiJdIDwgbXVbdHJ0ID09ICJTRk4iXSksDQogICAgICAgYnkgPSBHZW5laWRdDQpwMiA8LSBnZ3Bsb3QoZG11LncyW2RuLnVwID09IFRSVUUsIF0sDQogICAgICAgICAgICAgYWVzKHggPSB0cnQsDQogICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSB0cnQpKSArDQogICAgICAgIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV95IikgKw0KICAgICAgICBnZW9tX2xpbmUocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpKSArDQogICAgICAgIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArDQogICAgICAgIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJEaWZmZXJlbnRpYWxseSBFeHByZXNzZWQgR2VuZXMgYXQgV2VlayAyIikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIERvd25yZWd1bGF0ZWQgYnkgVVZCIikNCnRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQ0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC93Ml9kbl91cC50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA4LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcHJpbnQocDIpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMikNCmBgYA0KDQojIyBEaWQgdXAtZG93bi11cCB0cmVuZCBwZXJzaXN0Pw0KYGBge3IgZGVzZXEyX3cyc2lnbl9kZXNlcW5vcm1fcGxvdF9hbGxfZG5fdXAsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9DQpkcDEudG1wIDwtIGRwMVtkcDEkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MiRHZW5laWRbZG11LncyJGRuLnVwXSksIF0NCmRtdS50bXAgPC0gZG11W2RtdSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncyJEdlbmVpZFtkbXUudzIkZG4udXBdKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQpJbiBtYW55IG9mIHRoZXNlIGdlbmVzLCBVVkIrU0ZOIG1vdmVkIGNsb3NlciB0byBVVkIgb3ZlciB0aW1lLg0KDQojIyBIZWF0bWFwIGZvciBXZWVrIDIgZGlmZmVyZW50aWFsbHkgbWV0aHlsYXRlZCBnZW5lcw0KYGBge3IgdzJfaGVhdG1hcCwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCnVwLmRuLncyIDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoZG11LncyJEdlbmVpZFtkbXUudzIkdXAuZG5dKSkNCmRuLnVwLncyIDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoZG11LncyJEdlbmVpZFtkbXUudzIkZG4udXBdKSkNCmxsIDwtIHVuaXF1ZShjKHVwLmRuLncyLA0KICAgICAgICAgICAgICAgZG4udXAudzIpKQ0KIyAzNiBnZW5lcw0KDQpjb25fdXZiX3dlZWsyIDwtIGRhdGEudGFibGUoR2VuZWlkID0gcmVzX2Nvbl91dmJfd2VlazJAcm93bmFtZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMkZvbGRDaGFuZ2UgPSByZXNfY29uX3V2Yl93ZWVrMkBsaXN0RGF0YSRsb2cyRm9sZENoYW5nZSkNCg0Kc2ZuX3V2Yl93ZWVrMiA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IHJlc19zZm5fdXZiX3dlZWsyQHJvd25hbWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZzJGb2xkQ2hhbmdlID0gLXJlc19zZm5fdXZiX3dlZWsyQGxpc3REYXRhJGxvZzJGb2xkQ2hhbmdlKQ0KDQp0MSA8LSBtZXJnZShjb25fdXZiX3dlZWsyW2Nvbl91dmJfd2VlazIkR2VuZWlkICVpbiUgbGwsIF0sDQogICAgICAgICAgICBzZm5fdXZiX3dlZWsyW3Nmbl91dmJfd2VlazIkR2VuZWlkICVpbiUgbGwsIF0sDQogICAgICAgICAgICBieSA9ICJHZW5laWQiKQ0KY29sbmFtZXModDEpWzI6M10gPC0gYygiQ29udHJvbCB2cy4gVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIlVWQiB2cy4gU0ZOK1VWQiIpDQp0MSA8LSB0MVtvcmRlcih0MSRgQ29udHJvbCB2cy4gVVZCYCwNCiAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0Kd3JpdGUuY3N2KHQxLA0KICAgICAgICAgIGZpbGUgPSAidG1wL3cyX3NpZ25fY2hhbmdlcy5jc3YiLA0KICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQpsbCA8LSBtZWx0LmRhdGEudGFibGUoZGF0YSA9IHQxLA0KICAgICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IDI6MywNCiAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIkNvbXBhcmlzb24iLA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiR2VuZSBFeHByZXNzaW9uIERpZmYiKQ0KbGwkQ29tcGFyaXNvbiA8LSBmYWN0b3IobGwkQ29tcGFyaXNvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNvbnRyb2wgdnMuIFVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIgdnMuIFNGTitVVkIiKSkNCmx2bHMgPC0gbGxbbGwkQ29tcGFyaXNvbiA9PSAiQ29udHJvbCB2cy4gVVZCIiwgXQ0KbGwkR2VuZWlkIDwtIGZhY3RvcihsbCRHZW5laWQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGx2bHMkR2VuZWlkW29yZGVyKGx2bHMkYEdlbmUgRXhwcmVzc2lvbiBEaWZmYCldKQ0KDQojIEFkZCBkZW5kcm9ncmFtLS0tLQ0KZHQuZG5kciA8LSBkYXRhLmZyYW1lKHQxW0dlbmVpZCAlaW4lIGxldmVscyhsbCRHZW5laWQpLCBdKQ0Kcm93bmFtZXMoZHQuZG5kcikgPC0gZHQuZG5kciRHZW5lDQpkdC5kbmRyIDwtIGR0LmRuZHJbLCAtMV0NCg0KIyBDb21wdXRlIGRpc3RhbmNlcyBiZXR3ZWVuIGdlbmVzLS0tLQ0Kc2FtcGxlRGlzdHMgPC0gZGlzdChkdC5kbmRyKQ0KDQojIE1ha2UgZGVuZHJvZ3JhbSBkYXRhLS0tLQ0KZGhjIDwtIGFzLmRlbmRyb2dyYW0oaGNsdXN0KGQgPSBzYW1wbGVEaXN0cyksDQogICAgICAgICAgICAgICAgICAgICBob3JpeiA9IFRSVUUpDQpkZGF0YSA8LSBkZW5kcm9fZGF0YShkaGMsIA0KICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZWN0YW5nbGUiKQ0KDQojIFNlZ21lbnQgZGF0YS0tLS0NCmR0cDEgPC0gc2VnbWVudChkZGF0YSkNCg0KIyBIaXRtYXAgZGF0YS0tLS0NCmR0cDIgPC0gbGwNCmR0cDIkR2VuZWlkIDwtIGZhY3RvcihkdHAyJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBkZGF0YSRsYWJlbHMkbGFiZWwpDQoNCm9mZnNldC5zaXplIDwtIDQNCg0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkdHAyKSArDQogIGNvb3JkX3BvbGFyKCJ5IiwNCiAgICAgICAgICAgICAgc3RhcnQgPSAtMC4zLA0KICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAtMSkgKw0KICBnZW9tX3RpbGUoYWVzKHggPSAgYXMubnVtZXJpYyhDb21wYXJpc29uKSwNCiAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLCANCiAgICAgICAgICAgICAgICBmaWxsID0gYEdlbmUgRXhwcmVzc2lvbiBEaWZmYCksDQogICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBkdHAyW0NvbXBhcmlzb24gPT0gIkNvbnRyb2wgdnMuIFVWQiIsIF0sDQogICAgICAgICAgICBhZXMoeCA9IHJlcCgxLjc1LA0KICAgICAgICAgICAgICAgICAgICAgICAgbmxldmVscyhHZW5laWQpKSwNCiAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgIGFuZ2xlID0gOTAgKyBzZXEoZnJvbSA9IDMwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSAzMzAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gbmxldmVscyhHZW5laWQpKVthcy5udW1lcmljKEdlbmVpZCldICsgDQogICAgICAgICAgICAgICAgICBvZmZzZXQuc2l6ZSwNCiAgICAgICAgICAgICAgICBsYWJlbCA9IHVuaXF1ZShHZW5laWQpKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMCkgKw0KICBnZW9tX3RleHQoZGF0YSA9IGR0cDJbR2VuZWlkID09IGxldmVscyhkdHAyJEdlbmVpZClbMV0sIF0sDQogICAgICAgICAgICBhZXMoeCA9IDE6bmxldmVscyhDb21wYXJpc29uKSwNCiAgICAgICAgICAgICAgICB5ID0gcmVwKC1vZmZzZXQuc2l6ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5sZXZlbHMoQ29tcGFyaXNvbikpLA0KICAgICAgICAgICAgICAgIGFuZ2xlID0gMCwNCiAgICAgICAgICAgICAgICBsYWJlbCA9IGxldmVscyhDb21wYXJpc29uKSksDQogICAgICAgICAgICBoanVzdCA9IDEsDQogICAgICAgICAgICBzaXplID0gNSkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAicmVkIiwgDQogICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZ3JlZW4iLCANCiAgICAgICAgICAgICAgICAgICAgICAgbWlkID0gImdyZXkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAwLCANCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIiKSArDQogIHNjYWxlX3lfZGlzY3JldGUoIiIsDQogICAgICAgICAgICAgICAgICAgZXhwYW5kID0gYygwLCAwKSkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLA0KICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLA0KICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCAiaW4iKSwNCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuMywgImluIikpICsNCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBkdHAxLA0KICAgICAgICAgICAgICAgYWVzKHggPSAtc3FydCh5KSArIDAuNSwNCiAgICAgICAgICAgICAgICAgICB5ID0geCwgDQogICAgICAgICAgICAgICAgICAgeGVuZCA9IC1zcXJ0KHllbmQpICsgMC41LA0KICAgICAgICAgICAgICAgICAgIHllbmQgPSB4ZW5kKSwNCiAgICAgICAgICAgICAgIHNpemUgPSAxKSANCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2tpbl91YnZfdzJfc2ZuX2hpdG1hcF93aXRoX3BoeWxvLnRpZmYiLA0KICAgICBoZWlnaHQgPSA4LA0KICAgICB3aWR0aCA9IDgsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwbG90KHAxKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDEpDQpgYGANCg0KIyMgVmVubiBEaWFncmFtLCBXZWVrIDINCmBgYHtyIHcyLXZlbm4sIGZpZy5oZWlnaHQ9NixmaWcud2lkdGg9NH0NCiMgMS4gQ3RybCB2cy4gVVZCDQojIGFkanVzdGVkIHAtdmFsdWUgPCAwLjENCiMgTEZDID4gMCAodXApICAgICAgIDogMTU0NiwgOSUNCiMgTEZDIDwgMCAoZG93bikgICAgIDogMTUzNywgOC45JQ0KIyAyMyBnZW5lcyBkb3duLXVwLWRvd24NCg0KIyAyLiBTRk4rVVZCIHZzLiBVVkINCiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQ0KIyBMRkMgPiAwICh1cCkgICAgICAgOiAyNiwgMC4xNSUNCiMgTEZDIDwgMCAoZG93bikgICAgIDogMzUsIDAuMiUNCiMgMTMgZ2VucyB1cC1kb3duLXVwDQoNCnAxIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9jaXJjbGUoYWVzKHgwID0gYygxLCAyLCAxLCAyKSwNCiAgICAgICAgICAgICAgICAgIHkwID0gYygxLCAxLCA0LCA0KSwNCiAgICAgICAgICAgICAgICAgIHIgPSByZXAoMSwgNCksDQogICAgICAgICAgICAgICAgICBjb2xvciA9IGZhY3RvcihjKDIsIDEsIDEsIDIpKSksDQogICAgICAgICAgICAgIHNpemUgPSAyKSArDQogIGdlb21fdGV4dChhZXMoeCA9IHJlcChjKDAuNSwgMS41LCAyLjUpLCAyKSwNCiAgICAgICAgICAgICAgICB5ID0gcmVwKGMoMSwgNCksIGVhY2ggPSAzKSwNCiAgICAgICAgICAgICAgICBsYWJlbCA9IGZvcm1hdChjKDI2LCAxMywgMzUsIDE1NDYsIDIzLCAxNTM3KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaWcubWFyayA9ICIsIikpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJncmVlbiIsICJyZWQiKSkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCnRpZmYoZmlsZW5hbWUgPSAidG1wL3NraW5fdWJ2X3Nmbl93Ml92ZW5uLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDQsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwbG90KHAxKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDEpDQpgYGANCg0KDQojIyBJbnRlcmFjdGlvbnMgdGVybXMNClRlc3RzIGlmIHRoZSBlZmZlY3Qgb2YgTk9UIHRyZWF0aW5nIHdpdGggVVZCIHZzLiB0cmVhdGluZyB3aXRoIFVWQiBpcyBkaWZmZXJlbnQgYXQgV2VlayAxNSBjb21wYXJlZCB0byBXZWVrIDI6ICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV9yZXN1bHRzX2ludF9jb25fdXZifQ0KcmVzX2ludF9jb25fdXZiX3dlZWsgPC0gcmVzdWx0cyhkZHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gInRpbWUxNXcudHJ0Q09OIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfaW50X2Nvbl91dmJfd2VlayA8LSByZXNfaW50X2Nvbl91dmJfd2Vla1tvcmRlcihyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpwcmludChyZXNfaW50X2Nvbl91dmJfd2VlaykNCnN1bW1hcnkocmVzX2ludF9jb25fdXZiX3dlZWspDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQoNCiMgTUEgcGxvdA0KcHJpbnQocGxvdE1BKHJlc19pbnRfY29uX3V2Yl93ZWVrLA0KICAgICAgICAgICAgIG1haW4gPSAiKENvbnRyb2wgdnMuIFVWQikgeCBUSW1lIEludGVyYWN0aW9uIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOSkpDQoNCmBgYA0KDQpUZXN0cyBpZiB0aGUgZWZmZWN0IG9mIHRyZWF0aW5nIHdpdGggVVZCK1NGTiB2cy4gdHJlYXRpbmcgd2l0aCBVVkIgaXMgZGlmZmVyZW50IGF0IFdlZWsgMTUgY29tcGFyZWQgdG8gV2VlayAyOiAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfcmVzdWx0c19pbnRfc2ZuX3V2Yn0NCnJlc19pbnRfc2ZuX3V2Yl93ZWVrIDwtIHJlc3VsdHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJ0aW1lMTV3LnRydFNGTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2ludF9zZm5fdXZiX3dlZWsgPC0gcmVzX2ludF9zZm5fdXZiX3dlZWtbb3JkZXIocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0KcHJpbnQocmVzX2ludF9zZm5fdXZiX3dlZWspDQpzdW1tYXJ5KHJlc19pbnRfc2ZuX3V2Yl93ZWVrKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCnByaW50KHBsb3RNQShyZXNfaW50X3Nmbl91dmJfd2VlaykpDQoNCiMgTk9URTogc2FtZSBhcyANCiMgcmVzIDwtIHJlc3VsdHMoZGRzLCANCiMgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KQ0KIyByZXMgPC0gcmVzW29yZGVyKHJlcyRwYWRqLCBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCiMgcmVzDQpgYGANCg0KKipOT1RFKio6IEJ5IGRlZmF1bHQsIHRoZSAqKnJlc3VsdHMoZGRzKSoqKiBwcmludHMgdGhlIHJlc3VsdHMgZm9yIHRoZSBsYXN0IGxldmVsIG9mIHRoZSBsYXN0IHRlcm0sIGkuZS4gaGVyZSBpdCB3YXMgZm9yIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybSBTRk4gdnMuIFVWQiBhdCBXZWVrIDE1IHZzLiBXZWVrIDIuDQogICAgICAgDQojIEdlbmVzIHdpdGggYm90aCBpbnRlcmFjdGlvbnMgYmVpbmcgc2lnbmlmaWNhbnQNCmBgYHtyIHNpZ25faW50fQ0KbGdlbmUuY29uIDwtIHVuaXF1ZShyZXNfaW50X2Nvbl91dmJfd2Vla0Byb3duYW1lc1tyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xXSkNCmxnZW5lLnNmbiA8LSB1bmlxdWUocmVzX2ludF9zZm5fdXZiX3dlZWtAcm93bmFtZXNbcmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMV0pDQpsZ2VuZSA8LSBsZ2VuZS5jb25bbGdlbmUuY29uICVpbiUgbGdlbmUuc2ZuXQ0KbGdlbmUgPC0gbGdlbmVbIWlzLm5hKGxnZW5lKV0NCmxnZW5lDQpgYGANCg0KICAgICAgIA0KUGxvdCBvZiBERVNlcS1ub3JtYWxpemVkY291bnRzIG9mIGdlbmVzIHdpdGggc21hbGxlc3QgYWRqdXN0ZWQgcC12YWx1ZSBmb3IgdGhlIGludGVyYWN0aW9uIHRlcm06ICAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfdG9wOV9kZXNlcW5vcm0sIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KIyBHZXQgdGhlIERFU2VxLW5vcm1hbGl6ZSBjb3VudHMNCmRwMSA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOmxlbmd0aChsZ2VuZSkpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygidHJ0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiksDQogICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUUlVFKQ0KICBkcDFbW2ldXSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlID0gcm93bmFtZXMob3V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvdXQpDQp9DQpkcDEgPC0gcmJpbmRsaXN0KGRwMSkNCmRwMSR0cnQgPC0gZmFjdG9yKGRwMSR0cnQsDQogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KZHAxJHRpbWUgPC0gZmFjdG9yKGRwMSR0aW1lLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2VlayAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IikpDQpkcDEkR2VuZWlkIDwtIGZhY3RvcihkcDEkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbGdlbmUpDQpkcDFbLCBtdSA6PSBtZWFuKGNvdW50LA0KICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLA0KICAgIGJ5ID0gYygiR2VuZWlkIiwNCiAgICAgICAgICAgInRydCIsDQogICAgICAgICAgICJ0aW1lIildDQpkbXUgPC0gdW5pcXVlKGRwMVssIC1jKCJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAiY291bnQiKV0pDQoNCnAxIDwtIGdncGxvdChkcDEsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUsDQogICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgIGNvbG91ciA9IHRydCksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICBhbHBoYSA9IDAuNSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJERVNlcS1Ob3JtYWxpemVkIENvdW50cyIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikNCnByaW50KHAxKQ0KYGBgDQogICAgICANCkNvbXBhcmUgdG8gdGhlIHBsb3Qgb2YgVFBNLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgd2l0aCBzbWFsbGVzdCBhZGp1c3RlZCBwLXZhbHVlIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybTogICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV90cG1ub3JtLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCiMgRXhhbWluZSBUUE0gdmFsdWVzIGZvciB0aGUgc2FtZSBnZW5lcw0KdG1wIDwtIHRwbVtHZW5laWQgJWluJSBsZ2VuZSwgXQ0KdG1wJEdlbmVpZCA8LSBmYWN0b3IodG1wJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lKQ0KdG1wIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdG1wLA0KICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KdG1wIDwtIG1lcmdlKGRtZXRhLA0KICAgICAgICAgICAgIHRtcCwNCiAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQ0KDQpwMSA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywNCiAgICAgICAgICAgICAgICAgeSA9IFRQTSwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBUcmVhdG1lbnQpKSArDQogIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKQ0KcGxvdChwMSkNCmBgYA0KDQojIFNlc3Npb24gSW5mb3JtYXRpb24NCmBgYHtyIGluZm8sZXZhbD1UUlVFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBg